package com.example.common.grpc;

import com.example.common.constants.ServiceNames;
import com.example.game.proto.internal.SrvReq;
import com.example.game.proto.internal.SrvResp;
import io.grpc.ManagedChannel;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.ArrayList;

/**
 * gRPC客户端管理器
 * 负责管理多个服务实例的客户端连接和负载均衡
 * 
 * @author: Allen
 * @create: 2025/7/3 22:40
 * @description: gRPC客户端管理器
 **/
@Slf4j
@Component
public class GrpcClientManager {
    
    @Autowired
    private ServerIdLoadBalancer loadBalancer;
    
    @Autowired
    private ServerIdGenerator serverIdGenerator;
    
    @PostConstruct
    public void init() {
        log.info("gRPC客户端管理器初始化完成，当前服务器ID: {}", serverIdGenerator.getServerId());
    }
    
    /**
     * 同步调用指定服务类型
     */
    public SrvResp callService(ServiceNames serviceType, SrvReq request) {
        return callService(serviceType, request, ServerIdLoadBalancer.LoadBalanceStrategy.RANDOM);
    }
    
    /**
     * 同步调用指定服务类型（带负载均衡策略）
     */
    public SrvResp callService(ServiceNames serviceType, SrvReq request, 
                              ServerIdLoadBalancer.LoadBalanceStrategy strategy) {
        ServerIdLoadBalancer.ServerInstance instance = loadBalancer.getInstanceByServiceType(serviceType, strategy);
        if (instance == null) {
            throw new RuntimeException("没有可用的" + serviceType + "服务实例");
        }
        
        try {
            log.debug("调用服务: {} -> 服务器ID: {}", serviceType, instance.getServerId());
            return instance.getStub().process(request);
        } catch (Exception e) {
            log.error("调用服务失败: {} -> 服务器ID: {}", serviceType, instance.getServerId(), e);
            // 标记实例为不健康
            instance.setHealthy(false);
            throw new RuntimeException("调用服务失败: " + serviceType, e);
        }
    }
    
    /**
     * 心跳检测调用
     */
    public SrvResp callHeartbeat(ServiceNames serviceType, SrvReq request) {
        return callHeartbeat(serviceType, request, ServerIdLoadBalancer.LoadBalanceStrategy.ROUND_ROBIN);
    }
    
    /**
     * 心跳检测调用（带负载均衡策略）
     */
    public SrvResp callHeartbeat(ServiceNames serviceType, SrvReq request,
                                         ServerIdLoadBalancer.LoadBalanceStrategy strategy) {
        ServerIdLoadBalancer.ServerInstance instance = loadBalancer.getInstanceByServiceType(serviceType, strategy);
        if (instance == null) {
            throw new RuntimeException("没有可用的" + serviceType + "服务实例");
        }
        
        try {
            log.debug("心跳检测: {} -> 服务器ID: {}", serviceType, instance.getServerId());
            return instance.getStub().heartbeat(request);
        } catch (Exception e) {
            log.error("心跳检测失败: {} -> 服务器ID: {}", serviceType, instance.getServerId(), e);
            // 标记实例为不健康
            instance.setHealthy(false);
            throw new RuntimeException("心跳检测失败: " + serviceType, e);
        }
    }
    
    /**
     * 异步调用指定服务类型
     */
    public void callServiceAsync(ServiceNames serviceType, SrvReq request, StreamObserver<SrvResp> responseObserver) {
        callServiceAsync(serviceType, request, responseObserver, ServerIdLoadBalancer.LoadBalanceStrategy.ROUND_ROBIN);
    }
    
    /**
     * 异步调用指定服务类型（带负载均衡策略）
     */
    public void callServiceAsync(ServiceNames serviceType, SrvReq request, 
                                StreamObserver<SrvResp> responseObserver,
                                ServerIdLoadBalancer.LoadBalanceStrategy strategy) {
        ServerIdLoadBalancer.ServerInstance instance = loadBalancer.getInstanceByServiceType(serviceType, strategy);
        if (instance == null) {
            responseObserver.onError(new RuntimeException("没有可用的" + serviceType + "服务实例"));
            return;
        }
        
        try {
            log.debug("异步调用服务: {} -> 服务器ID: {}", serviceType, instance.getServerId());
            instance.getAsyncStub().process(request, responseObserver);
        } catch (Exception e) {
            log.error("异步调用服务失败: {} -> 服务器ID: {}", serviceType, instance.getServerId(), e);
            instance.setHealthy(false);
            responseObserver.onError(e);
        }
    }
    
    /**
     * 异步心跳检测调用
     */
    public void callHeartbeatAsync(ServiceNames serviceType, SrvReq request,
                                  StreamObserver<SrvResp> responseObserver) {
        callHeartbeatAsync(serviceType, request, responseObserver, ServerIdLoadBalancer.LoadBalanceStrategy.ROUND_ROBIN);
    }
    
    /**
     * 异步心跳检测调用（带负载均衡策略）
     */
    public void callHeartbeatAsync(ServiceNames serviceType, SrvReq request,
                                  StreamObserver<SrvResp> responseObserver,
                                  ServerIdLoadBalancer.LoadBalanceStrategy strategy) {
        ServerIdLoadBalancer.ServerInstance instance = loadBalancer.getInstanceByServiceType(serviceType, strategy);
        if (instance == null) {
            responseObserver.onError(new RuntimeException("没有可用的" + serviceType + "服务实例"));
            return;
        }
        
        try {
            log.debug("异步心跳检测: {} -> 服务器ID: {}", serviceType, instance.getServerId());
            instance.getAsyncStub().heartbeat(request, responseObserver);
        } catch (Exception e) {
            log.error("异步心跳检测失败: {} -> 服务器ID: {}", serviceType, instance.getServerId(), e);
            instance.setHealthy(false);
            responseObserver.onError(e);
        }
    }
    
    /**
     * 调用指定服务器ID的服务
     */
    public SrvResp callServiceByServerId(int serverId, SrvReq request) {
        ServerIdLoadBalancer.ServerInstance instance = loadBalancer.getInstanceByServerId(serverId);
        if (instance == null) {
            throw new RuntimeException("服务器ID不存在: " + serverId);
        }
        
        try {
            log.debug("调用指定服务器: 服务器ID: {}", serverId);
            return instance.getStub().process(request);
        } catch (Exception e) {
            log.error("调用指定服务器失败: 服务器ID: {}", serverId, e);
            instance.setHealthy(false);
            throw new RuntimeException("调用指定服务器失败: " + serverId, e);
        }
    }
    
    /**
     * 调用指定服务器ID的心跳检测
     */
    public SrvResp callHeartbeatByServerId(int serverId, SrvReq request) {
        ServerIdLoadBalancer.ServerInstance instance = loadBalancer.getInstanceByServerId(serverId);
        if (instance == null) {
            throw new RuntimeException("服务器ID不存在: " + serverId);
        }
        
        try {
            log.debug("调用指定服务器心跳: 服务器ID: {}", serverId);
            return instance.getStub().heartbeat(request);
        } catch (Exception e) {
            log.error("调用指定服务器心跳失败: 服务器ID: {}", serverId, e);
            instance.setHealthy(false);
            throw new RuntimeException("调用指定服务器心跳失败: " + serverId, e);
        }
    }
    
    /**
     * 异步调用指定服务器ID的服务
     */
    public void callServiceByServerIdAsync(int serverId, SrvReq request, StreamObserver<SrvResp> responseObserver) {
        ServerIdLoadBalancer.ServerInstance instance = loadBalancer.getInstanceByServerId(serverId);
        if (instance == null) {
            responseObserver.onError(new RuntimeException("服务器ID不存在: " + serverId));
            return;
        }
        
        try {
            log.debug("异步调用指定服务器: 服务器ID: {}", serverId);
            instance.getAsyncStub().process(request, responseObserver);
        } catch (Exception e) {
            log.error("异步调用指定服务器失败: 服务器ID: {}", serverId, e);
            instance.setHealthy(false);
            responseObserver.onError(e);
        }
    }
    
    /**
     * 批量调用服务（使用CompletableFuture）
     */
    public CompletableFuture<SrvResp> callServiceAsync(ServiceNames serviceType, SrvReq request) {
        CompletableFuture<SrvResp> future = new CompletableFuture<>();
        
        callServiceAsync(serviceType, request, new DefaultResponseObserverResp());
        
        return future;
    }

    /**
     * 获取所有可用的服务实例
     */
    public List<ServerIdLoadBalancer.ServerInstance> getAvailableInstances(ServiceNames serviceType) {
        return loadBalancer.serviceInstances.get(serviceType).stream()
                .filter(ServerIdLoadBalancer.ServerInstance::isHealthy)
                .collect(Collectors.toList());
    }
    
    /**
     * 获取服务统计信息
     */
    public ServerIdLoadBalancer.ServiceStats getServiceStats(ServiceNames serviceType) {
        return loadBalancer.getServiceStats().get(serviceType);
    }
    
    /**
     * 获取当前服务器ID
     */
    public int getCurrentServerId() {
        return serverIdGenerator.getServerId();
    }
    
    /**
     * 获取当前服务类型
     */
    public ServiceNames getCurrentServiceType() {
        return serverIdGenerator.getServiceType();
    }
    
    /**
     * 定期健康检查
     */
    //@Scheduled(fixedRate = 30000) // 每30秒检查一次
    public void healthCheck() {
        loadBalancer.healthCheck();
        
        // 打印服务统计信息
        Map<ServiceNames, ServerIdLoadBalancer.ServiceStats> stats = loadBalancer.getServiceStats();
        for (Map.Entry<ServiceNames, ServerIdLoadBalancer.ServiceStats> entry : stats.entrySet()) {
            ServiceNames serviceType = entry.getKey();
            ServerIdLoadBalancer.ServiceStats stat = entry.getValue();
            log.info("服务统计: {} -> {}", serviceType, stat);
        }
    }
    

    /**
     * 发送消息到指定服务类型（使用负载均衡）
     * 
     * @param serviceType 目标服务类型
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufData protobuf消息的二进制数据
     * @return 响应消息
     */
    public SrvResp sendMessage(ServiceNames serviceType, int code, int userId, byte[] protobufData) {
        return sendMessage(serviceType, code, userId, protobufData, ServerIdLoadBalancer.LoadBalanceStrategy.ROUND_ROBIN);
    }
    
    /**
     * 发送消息到指定服务类型（带负载均衡策略）
     * 
     * @param serviceType 目标服务类型
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufData protobuf消息的二进制数据
     * @param strategy 负载均衡策略
     * @return 响应消息
     */
    public SrvResp sendMessage(ServiceNames serviceType, int code, int userId, byte[] protobufData,
                              ServerIdLoadBalancer.LoadBalanceStrategy strategy) {
        int currentServerId = serverIdGenerator.getServerId();
        SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, protobufData);
        return callService(serviceType, request, strategy);
    }
    
    /**
     * 发送消息到指定服务器ID
     * 
     * @param targetServerId 目标服务器ID
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufData protobuf消息的二进制数据
     * @return 响应消息
     */
    public SrvResp sendMessageToServer(int targetServerId, int code, int userId, byte[] protobufData) {
        int currentServerId = serverIdGenerator.getServerId();
        SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, protobufData);
        return callServiceByServerId(targetServerId, request);
    }
    
    /**
     * 发送消息到指定服务类型和服务器ID
     * 
     * @param serviceType 目标服务类型
     * @param targetServerId 目标服务器ID
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufData protobuf消息的二进制数据
     * @return 响应消息
     */
    public SrvResp sendMessageToServiceAndServer(ServiceNames serviceType, int targetServerId, 
                                                int code, int userId, byte[] protobufData) {
        // 验证目标服务器ID是否属于指定的服务类型
        ServerIdLoadBalancer.ServerInstance instance = loadBalancer.getInstanceByServerId(targetServerId);
        if (instance == null) {
            throw new RuntimeException("服务器ID不存在: " + targetServerId);
        }
        
        if (instance.getServiceType() != serviceType) {
            throw new RuntimeException("服务器ID " + targetServerId + " 不属于服务类型 " + serviceType);
        }
        
        return sendMessageToServer(targetServerId, code, userId, protobufData);
    }
    
    /**
     * 异步发送消息到指定服务类型
     * 
     * @param serviceType 目标服务类型
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufData protobuf消息的二进制数据
     * @param responseObserver 响应观察者
     */
    public void sendMessageAsync(ServiceNames serviceType, int code, int userId, byte[] protobufData,
                                StreamObserver<SrvResp> responseObserver) {
        sendMessageAsync(serviceType, code, userId, protobufData, responseObserver, 
                        ServerIdLoadBalancer.LoadBalanceStrategy.ROUND_ROBIN);
    }
    
    /**
     * 异步发送消息到指定服务类型（带负载均衡策略）
     * 
     * @param serviceType 目标服务类型
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufData protobuf消息的二进制数据
     * @param responseObserver 响应观察者
     * @param strategy 负载均衡策略
     */
    public void sendMessageAsync(ServiceNames serviceType, int code, int userId, byte[] protobufData,
                                StreamObserver<SrvResp> responseObserver,
                                ServerIdLoadBalancer.LoadBalanceStrategy strategy) {
        int currentServerId = serverIdGenerator.getServerId();
        SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, protobufData);
        callServiceAsync(serviceType, request, responseObserver, strategy);
    }
    
    /**
     * 异步发送消息到指定服务器ID
     * 
     * @param targetServerId 目标服务器ID
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufData protobuf消息的二进制数据
     * @param responseObserver 响应观察者
     */
    public void sendMessageToServerAsync(int targetServerId, int code, int userId, byte[] protobufData,
                                        StreamObserver<SrvResp> responseObserver) {
        int currentServerId = serverIdGenerator.getServerId();
        SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, protobufData);
        callServiceByServerIdAsync(targetServerId, request, responseObserver);
    }
    
    /**
     * 异步发送消息到指定服务类型和服务器ID
     * 
     * @param serviceType 目标服务类型
     * @param targetServerId 目标服务器ID
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufData protobuf消息的二进制数据
     * @param responseObserver 响应观察者
     */
    public void sendMessageToServiceAndServerAsync(ServiceNames serviceType, int targetServerId,
                                                  int code, int userId, byte[] protobufData,
                                                  StreamObserver<SrvResp> responseObserver) {
        // 验证目标服务器ID是否属于指定的服务类型
        ServerIdLoadBalancer.ServerInstance instance = loadBalancer.getInstanceByServerId(targetServerId);
        if (instance == null) {
            responseObserver.onError(new RuntimeException("服务器ID不存在: " + targetServerId));
            return;
        }
        
        if (instance.getServiceType() != serviceType) {
            responseObserver.onError(new RuntimeException("服务器ID " + targetServerId + " 不属于服务类型 " + serviceType));
            return;
        }
        
        sendMessageToServerAsync(targetServerId, code, userId, protobufData, responseObserver);
    }
    
    /**
     * 使用CompletableFuture异步发送消息到指定服务类型
     * 
     * @param serviceType 目标服务类型
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufData protobuf消息的二进制数据
     * @return CompletableFuture<SrvResp>
     */
    public CompletableFuture<SrvResp> sendMessageAsync(ServiceNames serviceType, int code, int userId, byte[] protobufData) {
        int currentServerId = serverIdGenerator.getServerId();
        SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, protobufData);
        return callServiceAsync(serviceType, request);
    }

    
    /**
     * 广播消息到指定服务类型的所有实例
     * 
     * @param serviceType 目标服务类型
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufData protobuf消息的二进制数据
     * @return 所有实例的响应列表
     */
    public List<SrvResp> broadcastMessage(ServiceNames serviceType, int code, int userId, byte[] protobufData) {
        List<ServerIdLoadBalancer.ServerInstance> instances = getAvailableInstances(serviceType);
        List<SrvResp> responses = new ArrayList<>();
        
        for (ServerIdLoadBalancer.ServerInstance instance : instances) {
            try {
                SrvResp response = sendMessageToServer(instance.getServerId(), code, userId, protobufData);
                responses.add(response);
            } catch (Exception e) {
                log.error("广播消息到服务器{}失败", instance.getServerId(), e);
                // 可以选择是否将异常响应也加入列表
            }
        }
        
        return responses;
    }
    
    /**
     * 发送消息到指定服务类型（使用protobuf对象）
     * 
     * @param serviceType 目标服务类型
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufMessage protobuf消息对象
     * @return 响应消息
     */
    public SrvResp sendProtobufMessage(ServiceNames serviceType, int code, int userId, 
                                      com.google.protobuf.Message protobufMessage) {
        byte[] protobufData = protobufMessage != null ? protobufMessage.toByteArray() : new byte[0];
        return sendMessage(serviceType, code, userId, protobufData);
    }
    
    /**
     * 发送消息到指定服务器ID（使用protobuf对象）
     * 
     * @param targetServerId 目标服务器ID
     * @param code 协议号
     * @param userId 用户ID
     * @param protobufMessage protobuf消息对象
     * @return 响应消息
     */
    public SrvResp sendProtobufMessageToServer(int targetServerId, int code, int userId,
                                              com.google.protobuf.Message protobufMessage) {
        byte[] protobufData = protobufMessage != null ? protobufMessage.toByteArray() : new byte[0];
        return sendMessageToServer(targetServerId, code, userId, protobufData);
    }
} 